package fins

import (
	"errors"
	"io"
	"strconv"
	"strings"

	"gitee.com/acquisition_driver_development/magus_iot/magus/golib/sock"

	"gitee.com/acquisition_driver_development/magus_iot/magus/logs"

	hostlink "gitee.com/acquisition_driver_development/magus_iot/common_library/hostlink_0903"
)

type FinsMaster struct {
	hostlink.Master
	UintNum string
}

func (this *FinsMaster) Initialize(da2 string) (err error) {
	if strings.TrimSpace(da2) == "" {
		this.UintNum = "00"
	}
	dint, err := strconv.ParseUint(da2, 10, 32)
	if err != nil || dint > 31 {
		err = errors.New("unknown unitnumber: " + da2)
		return
	}
	switch len(da2) {
	case 1:
		this.UintNum = "0" + da2
	case 2:
		this.UintNum = da2
	default:
		err = errors.New("unknown unitnumber: " + da2)
		return
	}

	this.Master.Initialize()
	return
}

func (this *FinsMaster) MakeRequest(group *hostlink.Group) (cmd []byte) {
	fins := (hostlink.HK_TITLE + this.UintNum + hostlink.HK_HEADCODE +
		hostlink.HK_RESTIM + hostlink.HK_ICF + hostlink.HK_DA2 +
		hostlink.HK_SA2 + hostlink.HK_SID + hostlink.HK_READE + group.WordCode)

	fins += ToString(uint64(group.BeginAddress), 16, 4)
	if group.IfBite {
		fins += ToString(uint64(group.BeginBit), 16, 2)
	} else {
		fins += "00"
	}
	fins += ToString(uint64(group.Size), 16, 4)

	cmd = []byte(fins)
	return
}

func (this *FinsMaster) Write(conn io.Writer, data []byte) (n int, err error) {
	//校验
	fc1, fc2 := hostlink.FCS(data)
	data = append(data, fc1, fc2, 0x2A, 0x0D)
	n, err = conn.Write(data)
	logs.Debug("S: % 2X", data)

	return
}

func (this *FinsMaster) Read(conn io.Reader, pnum int, ifbit bool) (buf []byte, err error) {
	codecount := 27 //固定字节27位
	l := int(0)
	if ifbit {
		l = pnum*2 + codecount //每bit占两字节
	} else {
		l = pnum*4 + codecount
	}
	data := make([]byte, l)
	_, err = sock.ReadTimeout(conn, data, 2000)
	if err != nil {
		return
	}
	logs.Debug("R: % 2X", data)
	buf, err = this.CheckData(data)
	return
}

/*
*报文结构：
*	十六进制: 40 30 30 46 41 30 30 34 30 30 30 30 30 30 30 30 31 30 31 30 30 30 30 39 39 39 41 33 42 2A 0D
*	ASCII:  @00FA004000000001010000999A3B*
 */
func (this *FinsMaster) CheckData(data []byte) (buf []byte, err error) {
	l := len(data)
	if l < 27 {
		err = errors.New("data length error")
		return
	}
	if data[0] != '@' {
		err = errors.New("Recv code title wrong ," + string(data[:1]))
		return
	}
	if string(data[3:5]) != hostlink.HK_HEADCODE {
		err = errors.New("headcode error net be " + hostlink.HK_HEADCODE)
		return
	}

	if string(data[19:23]) != "0000" { //错误码
		err = errors.New("error code neet be 0000")
		return
	}

	//FCS校验
	fc1, fc2 := hostlink.FCS(data[:l-4])
	if data[l-4] != fc1 || data[l-3] != fc2 {
		err = errors.New("FCS error")
		return
	}

	return data[23 : l-4], err
}

/*
*@param
*i  	值
*base	进制
*prec	精度
 */
func ToString(i uint64, base int, prec int) string {
	s := strconv.FormatUint(i, base)
	l := len(s)
	if l < prec {
		for i := 0; i < prec-l; i++ {
			s = "0" + s
		}

	} else if l > prec {
		s = s[l-prec:]
	}
	return s
}
